;;; guile-openai --- An OpenAI API client for Guile
;;; Copyright © 2023 Andrew Whatson <whatson@tailcall.au>
;;;
;;; This file is part of guile-openai.
;;;
;;; guile-openai is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU Affero General Public License as
;;; published by the Free Software Foundation, either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; guile-openai is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; Affero General Public License for more details.
;;;
;;; You should have received a copy of the GNU Affero General Public
;;; License along with guile-openai.  If not, see
;;; <https://www.gnu.org/licenses/>.

(define-module (openai api image)
  #:use-module (openai client)
  #:use-module (openai utils multipart)
  #:use-module (ice-9 match)
  #:use-module (json record)
  #:use-module (pict base64)
  #:use-module (srfi srfi-71)
  #:use-module (web client)
  #:export (make-image-request
            json->image-request
            image-request->json
            image-request?
            image-request-prompt
            image-request-n
            image-request-size
            image-request-response-format
            image-request-user

            make-image-variation-request
            json->image-variation-request
            image-variation-request->multipart
            image-variation-request?
            image-variation-request-image
            image-variation-request-n
            image-variation-request-size
            image-variation-request-response-format
            image-variation-request-user

            make-image-edit-request
            json->image-edit-request
            image-edit-request->multipart
            image-edit-request?
            image-edit-request-image
            image-edit-request-mask
            image-edit-request-prompt
            image-edit-request-n
            image-edit-request-size
            image-edit-request-response-format
            image-edit-request-user

            make-image-response
            json->image-response
            image-response->json
            image-response?
            image-response-created
            image-response-data

            make-image-data
            json->image-data
            image-data->json
            image-data?
            image-data-url
            image-data-b64-json

            send-image-request
            send-image-edit-request
            send-image-variation-request
            fetch-image-data))

;; See https://platform.openai.com/docs/api-reference/images

(define-json-type <image-request>
  (prompt)
  (n)
  (size) ;; 256x256 512x512 1024x1024
  (response-format "response_format") ;; url b64_json
  (user))

(define-json-type <image-variation-request>
  (image)
  (n)
  (size) ;; 256x256 512x512 1024x1024
  (response-format "response_format") ;; url b64_json
  (user))

(define-json-type <image-edit-request>
  (image)
  (mask)
  (prompt)
  (n)
  (size) ;; 256x256 512x512 1024x1024
  (response-format "response_format") ;; url b64_json
  (user))

(define-json-type <image-response>
  (created)
  (data "data" #(<image-data>)))

(define-json-type <image-data>
  (url)
  (b64-json "b64_json"))

(define (image-variation-request->multipart request)
  (match request
    (($ <image-variation-request> image n size response-format user)
     (append (multipart-param 'n n)
             (multipart-param 'size size)
             (multipart-param 'response_format response-format)
             (multipart-param 'user user)
             (multipart-file 'image image)))))

(define (image-edit-request->multipart request)
  (match request
    (($ <image-edit-request> image mask prompt n size response-format user)
     (append (multipart-param 'prompt prompt)
             (multipart-param 'n n)
             (multipart-param 'size size)
             (multipart-param 'response_format response-format)
             (multipart-param 'user user)
             (multipart-file 'image image)
             (multipart-file 'mask mask)))))

(define (send-image-request request)
  (json->image-response
   (openai-post-json "/v1/images/generations"
                     (image-request->json request))))

(define (send-image-edit-request request)
  (json->image-response
   (openai-post-multipart "/v1/images/edits"
                          (image-edit-request->multipart request))))

(define (send-image-variation-request request)
  (json->image-response
   (openai-post-multipart "/v1/images/variations"
                          (image-variation-request->multipart request))))

(define (fetch-image-data img)
  (match img
    (($ <image-data> (? string? url))
     (let ((rsp bv (http-request url)))
       bv))
    (($ <image-data> _ (? string? b64))
     (base64-decode b64))))
